package com.truthbean.jutils.file;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 国际化字符串类
 * 
 * format(Class<?> clazz, String resource, Object...
 * objects)方法接受Class作为参数，用于寻找对应的资源文件。
 * 
 * 此类目的是强制资源资源提供和命名规范，模块化I18N资源管理。
 * 
 * formate方法将根据Locale.getDefault()，在指定类的包中以如下文件命名优先级查找国际化资源内容：
 * 
 * className + "_" + language1 + "_" + country1 + "_" + variant1 + ".i18n"
 * 
 * className + "_" + language1 + "_" + country1 + ".i18n"
 * 
 * className + "_" + language1 + ".i18n"
 * 
 * className + ".i18n"
 * 
 * 
 * 资源文件内容格式参考java.text.MessageFormat
 * 
 * 此类将缓存查询结果用于未来多次使用。
 * 
 * 执行java命令时加可参数,-Duser.language和-Duser.region来设置所在Locale
 * 
 * 
 * @author TruthBean
 * 
 */
public class I18NUtil {
    private static Map<String, String> CHARSET_MAP = new HashMap<>();
    static {
        CHARSET_MAP.put("zh_CN", "UTF-8");
        CHARSET_MAP.put("zh_HK", "UTF-8");
    }
    private final static Logger logger = LoggerFactory.getLogger(I18NUtil.class);
    public static final String RESOURCE_FILE_POSTFIX = ".i18n";
    private static final Map<String, String> NO_RESOURCE = Collections.emptyMap();

    private static Map<Class<?>, Map<String, String>> cache = Collections
            .synchronizedMap(new WeakHashMap<Class<?>, Map<String, String>>());

    /**
     * 格式化资源
     * 
     * @param clazz
     *            资源所依附的类
     * @param resource
     *            字符串资源名称
     * @param objects
     *            参数
     * @return 格式化结果
     */
    public static String format(Class<?> clazz, String resource, Object... objects) {
        String resource_string = getResourceString(clazz, resource);
        String builded = MessageFormat.format(resource_string, objects);
        if (logger.isDebugEnabled()) {
            logger.debug(clazz + " 资源名:" + resource + " 返回值:" + builded);
        }
        return builded;
    }

    private static String getResourceString(Class<?> clazz, String resource) {
        Map<String, String> resourceMap = cache.get(clazz);
        if (resourceMap == null) {
            synchronized (I18NUtil.class) {
                resourceMap = cache.get(clazz);
                if (resourceMap == null) {
                    resourceMap = loadRescoureceMap(clazz);
                    if (resourceMap != null) {
                        cache.put(clazz, resourceMap);
                    } else {
                        cache.put(clazz, NO_RESOURCE);
                        return warnAndReturnResource(clazz, resource);
                    }
                }
            }
        } else if (resourceMap == NO_RESOURCE) {
            return warnAndReturnResource(clazz, resource);
        }
        String string = resourceMap.get(resource);
        if (string != null) {
            return string;
        } else {
            return warnAndReturnResource(clazz, resource);
        }
    }

    private static String warnAndReturnResource(Class<?> clazz, String resource) {
        logger.warn("!" + clazz + "[" + resource + "]" + " 国际化资源未定义!", new Exception());
        return resource;
    }

    private static Map<String, String> loadRescoureceMap(Class<?> clazz) {
        String baseResourceFileName = clazz.getSimpleName();
        Map<String, String> ret = new HashMap<>();
        // 基本资源
        Map<String, String> baseMap = loadLocalResourceMap(clazz, baseResourceFileName);
        if (baseMap != null) {
            ret.putAll(baseMap);
        }

        Locale locale = Locale.getDefault();
        // 当前语言体系资源
        String languageResourceFileName = clazz.getSimpleName() + "_" + locale.getLanguage();
        Map<String, String> languageMap = loadLocalResourceMap(clazz, languageResourceFileName);
        if (languageMap != null) {
            ret.putAll(languageMap);
        }

        // 当前地理位置优先资源
        String localeResourceFileName = clazz.getSimpleName() + "_" + locale.getLanguage() + "_" + locale.getCountry();
        Map<String, String> localeMap = loadLocalResourceMap(clazz, localeResourceFileName);
        if (localeMap != null) {
            ret.putAll(localeMap);
        }
        // 变体资源
        String variant = locale.getVariant();
        if (!"".equals(variant)) {
            String localVariantResourceFileName = clazz.getSimpleName() + "_" + locale.getLanguage() + "_"
                    + locale.getCountry() + "_" + locale.getVariant();
            Map<String, String> localVariantLocaleMap = loadLocalResourceMap(clazz, localVariantResourceFileName);
            if (localVariantLocaleMap != null) {
                ret.putAll(localVariantLocaleMap);
            }
        }
        return ret.size() == 0 ? null : ret;
    }

    private static Map<String, String> loadLocalResourceMap(Class<?> clazz, String resourceFileName) {

        InputStream resourceAsStream = clazz.getResourceAsStream(resourceFileName + RESOURCE_FILE_POSTFIX);
        if (resourceAsStream != null) {
            Map<String, String> ret = new HashMap<>();
            Locale locale = Locale.getDefault();
            String charset = CHARSET_MAP.get(locale.getLanguage() + "_" + locale.getCountry());
            if (charset == null) {
                charset = "UTF-8";
            }
            BufferedReader r = new BufferedReader(new InputStreamReader(resourceAsStream, Charset.forName(charset)));
            String line = null;
            try {
                while ((line = r.readLine()) != null) {
                    if (line.trim().equals("")) {
                        continue;
                    }
                    String[] split = line.split("=", 2);
                    if (split.length != 2) {
                        logger.warn("无法解析国际化资源" + clazz + " " + resourceFileName + "[" + line + "]");
                        continue;
                    } else {
                        ret.put(split[0].trim(), split[1]);

                    }
                }
            } catch (Exception e) {
                logger.error("加载国际化资源异常", e);
            }
            return ret;
        } else {
            return null;
        }
    }

    /**
     * 对指定Class中的变量进行初始化
     * 
     * @param class1
     */
    public static void initClass(Class<?> clazz) {
        if (clazz == null) {
            throw new NullPointerException("class参数为null");
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        Map<String, String> rescoureceMap = loadRescoureceMap(clazz);
        if (rescoureceMap == null) {
            logger.error("未找到指定类的国际化资源:" + clazz.getName() + " 语言设置：" + Locale.getDefault());
        }
        for (Field field : declaredFields) {
            if (String.class.equals(field.getType()) && ifStaticField(field) && !isFinal(field)) {
                String string = rescoureceMap.get(field.getName());
                if (string != null) {
                    try {
                        field.setAccessible(true);
                        field.set(null, string);
                    } catch (Exception e) {
                        logger.warn("注入国际化资源异常" + clazz + " " + field, e);
                    }
                } else {
                    logger.info("未找到国际化资源！" + clazz + " " + field);
                    //
                }
            }
        }
    }

    private static boolean isFinal(Field field) {
        return Modifier.isFinal(field.getModifiers());
    }

    private static boolean ifStaticField(Field field) {
        boolean isStatic = Modifier.isStatic(field.getModifiers());
        return isStatic;
    }
}